/**
 * ZPAY支付签名工具类 - 负责支付接口签名和参数处理
 *
 * 开发人员：徐少洋
 * 开发时间：2025-11-05 至 2025-11-08
 * 模块职责：实现ZPAY支付平台的签名算法和参数处理，确保支付接口调用的安全性和正确性
 *
 * 技术要点：
 * - MD5签名算法实现，符合ZPAY官方规范
 * - 参数过滤和排序处理
 * - URL编码和查询字符串构建
 * - 支付回调验签机制
 *
 * 开发故事：负责支付系统的安全核心，实现了支付签名的完整逻辑，确保与ZPAY支付平台的无缝对接和交易安全性。
 */
package com.pbl.util;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

public final class ZpaySignUtil {
    private ZpaySignUtil() {}

    /**
     * 根据ZPAY规则进行md5签名（小写），过滤空值与sign、sign_type，按参数名升序拼接，最后+KEY
     */
    public static String buildSign(Map<String, String> params, String key) {
        Map<String, String> filtered = new HashMap<>();
        for (Map.Entry<String, String> e : params.entrySet()) {
            String k = e.getKey();
            String v = e.getValue();
            if (v == null || v.isEmpty()) continue;
            if ("sign".equalsIgnoreCase(k) || "sign_type".equalsIgnoreCase(k)) continue;
            filtered.put(k, v);
        }
        List<String> keys = new ArrayList<>(filtered.keySet());
        Collections.sort(keys);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < keys.size(); i++) {
            String k = keys.get(i);
            String v = filtered.get(k);
            if (i > 0) sb.append("&");
            sb.append(k).append("=").append(v);
        }
        // 按照文档：sign = md5(a=b&c=d&e=f + KEY)
        String base = sb.toString() + key;
        return Md5Util.md5Hex(base);
    }

    /**
     * 将参数拼接成查询字符串（不做url编码，按文档示例返回），也提供可选的编码版。
     */
    public static String toQueryString(Map<String, String> params, boolean urlEncode) {
        List<String> keys = new ArrayList<>(params.keySet());
        Collections.sort(keys);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < keys.size(); i++) {
            String k = keys.get(i);
            String v = params.get(k);
            if (i > 0) sb.append("&");
            if (urlEncode) {
                sb.append(encode(k)).append("=").append(encode(v));
            } else {
                sb.append(k).append("=").append(v);
            }
        }
        return sb.toString();
    }

    private static String encode(String s) {
        return URLEncoder.encode(s, StandardCharsets.UTF_8);
    }
}
